/*
 * Copyright 2013 Faisal Aslam.
 * All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This code is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3
 * only, as published by the Free Software Foundation.
 * 
 * This code is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License version 3 for more details (a copy is
 * included in the LICENSE file that accompanied this code).
 * 
 * You should have received a copy of the GNU General Public License
 * version 3 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Faisal Aslam (faisal.aslam AT gmail.com)
 * if you need additional information or have any questions.
 */
package org.parallelCompiler.modifyCF.logic;

import java.util.*;
import takatuka.classreader.dataObjs.*;
import takatuka.classreader.dataObjs.attribute.*;
import takatuka.classreader.logic.constants.JavaInstructionsOpcodes;
import takatuka.classreader.logic.factory.*;
import takatuka.optimizer.cpGlobalization.logic.util.Oracle;

/**
 * This is a test program. It generate random nop
 * in all the classes it has read and all the functions.
 *
 * @author Faisal Aslam
 */
public class AddNOPs {

    public void execute() {
        //if (true) return;
        ClassFileController cfContr = ClassFileController.getInstanceOf();
        for (int classIndex = 0; classIndex < cfContr.getCurrentSize(); classIndex++) {
            ClassFile cf = (ClassFile) cfContr.get(classIndex);
            MethodInfoController miContr = cf.getMethodInfoController();
            for (int methodIndex = 0; methodIndex < miContr.getCurrentSize(); methodIndex++) {
                if (methodIndex == 0) {
                    MethodInfo mInfo = (MethodInfo) miContr.get(methodIndex);
                    CodeAtt codeAtt = mInfo.getCodeAtt();
                    //removeLineNumberAtt(codeAtt);
                    addRandomlyNOP(codeAtt);
                }

            }
        }
    }

    private Instruction createInstr(CodeAtt codeAtt, int opCode) throws Exception {
        FactoryPlaceholder placeHolder = FactoryPlaceholder.getInstanceOf();
        FactoryFacade facade = placeHolder.getFactory();
        return facade.createInstruction(opCode, facade.createUn().trim(0), codeAtt);
    }

    private void addRandomlyNOP(CodeAtt codeAtt) {

        Vector<Instruction> instrVec = codeAtt.getInstructions();
        try {
            Random rm = new Random(System.currentTimeMillis());
            System.out.println("size =" + instrVec.size());
            int numberToAdd = 1;//instrVec.size() / 2;
            Instruction aload0 = createInstr(codeAtt, JavaInstructionsOpcodes.ALOAD_0);
            Instruction pop = createInstr(codeAtt, JavaInstructionsOpcodes.POP);
            
            for (int loop = 0; loop < numberToAdd; loop++) {
                int toAddIndex = 0;//rm.nextInt(instrVec.size() - 1);
                instrVec.add(toAddIndex, pop);
                instrVec.add(toAddIndex, aload0);
            }
        } catch (Exception d) {
            d.printStackTrace();
            System.exit(1);
        }

        codeAtt.setInstructions(instrVec);
    }

    private void removeLineNumberAtt(CodeAtt codeAtt) {
        AttributeInfoController attContr = codeAtt.getAttributes();
        for (int loop = 0; loop < attContr.getCurrentSize(); loop++) {
            AttributeInfo info = (AttributeInfo) attContr.get(loop);
            if (info instanceof LineNumberTableAtt) {
                attContr.remove(loop);
                break;
            }
        }
    }
}
